package wiki.xsx.core.jmeter.core.threadgroup;

import wiki.xsx.core.jmeter.core.JmeterFactory;
import wiki.xsx.core.jmeter.core.assertion.JmeterAssertion;
import wiki.xsx.core.jmeter.core.controller.JmeterLoopController;
import wiki.xsx.core.jmeter.core.postprocessor.JmeterPostProcessor;
import wiki.xsx.core.jmeter.core.preprocessor.JmeterPreProcessor;
import wiki.xsx.core.jmeter.core.result.JmeterResultCollector;
import wiki.xsx.core.jmeter.core.sampler.JmeterSampler;
import wiki.xsx.core.jmeter.core.util.JmeterOptional;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 默认线程组
 *
 * @author xsx
 * @date 2022/8/22
 * @since 1.8
 * <p>
 * Copyright (c) 2022 xsx All Rights Reserved.
 * easy-jmeter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 * http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * </p>
 */
@Data
@Accessors(chain = true)
public class JmeterDefaultThreadGroup implements JmeterThreadGroup {

    /**
     * 线程组名称
     */
    private String name;
    /**
     * 线程组注释
     */
    private String comment;
    /**
     * 线程数量/用户数（单位：个）
     */
    private Integer threadNum;
    /**
     * 到达线程数量的时间（单位：秒）
     * <p>0时表示立即开启</p>
     * <p>当threadNum=100，rampUp=10时，表示10秒内共开启100个线程，即每秒递增10个线程</p>
     */
    private Integer rampUp;
    /**
     * 是否相同用户
     */
    private Boolean isSameUser;
    /**
     * 是否启用调度器
     */
    private Boolean isScheduler;
    /**
     * 持续时间（单位：秒）
     */
    private Integer duration;
    /**
     * 启动延迟（单位：秒）
     */
    private Integer delay;

    /**
     * 循环控制器
     */
    private JmeterLoopController loopController;
    /**
     * 结果收集器
     */
    private JmeterResultCollector resultCollector;
    /**
     * 样本列表
     */
    private List<JmeterSampler> samplers;
    /**
     * 前置处理器列表
     */
    private List<JmeterPreProcessor> preProcessors;
    /**
     * 后置处理器列表
     */
    private List<JmeterPostProcessor> postProcessors;
    /**
     * 断言列表
     */
    private List<JmeterAssertion> assertions;

    /**
     * 无参构造
     */
    private JmeterDefaultThreadGroup() {
    }

    /**
     * 获取线程组实例
     *
     * @return 返回线程组实例
     */
    public static JmeterDefaultThreadGroup getInstance() {
        return new JmeterDefaultThreadGroup();
    }

    /**
     * 初始化样本容量
     *
     * @param initialCapacity 初始容量
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup initialSamplerCapacity(int initialCapacity) {
        this.samplers = new ArrayList<>(initialCapacity);
        return this;
    }

    /**
     * 初始化前置处理器容量
     *
     * @param initialCapacity 初始容量
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup initialPreProcessorCapacity(int initialCapacity) {
        this.preProcessors = new ArrayList<>(initialCapacity);
        return this;
    }

    /**
     * 初始化后置处理器容量
     *
     * @param initialCapacity 初始容量
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup initialPostProcessorCapacity(int initialCapacity) {
        this.postProcessors = new ArrayList<>(initialCapacity);
        return this;
    }

    /**
     * 初始化断言容量
     *
     * @param initialCapacity 初始容量
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup initialAssertionCapacity(int initialCapacity) {
        this.assertions = new ArrayList<>(initialCapacity);
        return this;
    }

    /**
     * 添加样本
     *
     * @param samplers 样本
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup addSampler(JmeterSampler... samplers) {
        // 如果样本列表为空，则初始化样本列表
        if (this.samplers == null) {
            // 初始化样本列表
            this.samplers = new ArrayList<>(10);
        }
        // 添加样本
        Collections.addAll(this.samplers, samplers);
        // 返回线程组
        return this;
    }

    /**
     * 添加前置处理器
     *
     * @param preProcessors 前置处理器
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup addPreProcessor(JmeterPreProcessor... preProcessors) {
        // 如果前置处理器列表为空，则初始化前置处理器列表
        if (this.preProcessors == null) {
            // 初始化前置处理器列表
            this.preProcessors = new ArrayList<>(10);
        }
        // 添加前置处理器
        Collections.addAll(this.preProcessors, preProcessors);
        // 返回线程组
        return this;
    }

    /**
     * 添加后置处理器
     *
     * @param postProcessors 后置处理器
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup addPostProcessor(JmeterPostProcessor... postProcessors) {
        // 如果后置处理器列表为空，则初始化后置处理器列表
        if (this.postProcessors == null) {
            // 初始化后置处理器列表
            this.postProcessors = new ArrayList<>(10);
        }
        // 添加后置处理器
        Collections.addAll(this.postProcessors, postProcessors);
        // 返回线程组
        return this;
    }

    /**
     * 添加断言
     *
     * @param assertions 断言
     * @return 返回线程组
     */
    public JmeterDefaultThreadGroup addAssertion(JmeterAssertion... assertions) {
        // 如果断言列表为空，则初始化断言列表
        if (this.assertions == null) {
            // 初始化断言列表
            this.assertions = new ArrayList<>(10);
        }
        // 添加断言
        Collections.addAll(this.assertions, assertions);
        // 返回线程组
        return this;
    }

    /**
     * 创建线程组
     *
     * @return 返回线程组配置树
     */
    @Override
    public HashTree create() {
        // 创建线程组配置树
        HashTree threadGroupTree = new ListedHashTree();
        // 添加线程组
        HashTree samplerTree = threadGroupTree.add(this.createThreadGroup());
        // 如果采样器不为空，则添加采样器
        JmeterOptional.ofNullable(this.samplers).ifPresent(
                v -> v.forEach(sampler -> samplerTree.add(sampler.create()))
        );
        // 如果结果收集器不为空，则添加结果收集器
        JmeterOptional.ofNullable(this.resultCollector).ifPresent(
                v -> v.getConfigs().forEach(collector -> samplerTree.add(collector.create()))
        );
        // 如果前置处理器列表不为空，则添加前置处理器
        JmeterOptional.ofNullable(this.preProcessors).ifPresent(
                v -> v.forEach(preProcessor -> samplerTree.add(preProcessor.create()))
        );
        // 如果后置处理器列表不为空，则添加后置处理器
        JmeterOptional.ofNullable(this.postProcessors).ifPresent(
                v -> v.forEach(postProcessor -> samplerTree.add(postProcessor.create()))
        );
        // 如果断言列表不为空，则添加断言
        JmeterOptional.ofNullable(this.assertions).ifPresent(
                v -> v.forEach(assertion -> samplerTree.add(assertion.create()))
        );
        // 返回线程组配置树
        return threadGroupTree;
    }

    /**
     * 创建线程组
     *
     * @return 返回线程组
     */
    private ThreadGroup createThreadGroup() {
        // 创建线程组
        ThreadGroup threadGroup = new ThreadGroup();
        // 设置测试类名称
        threadGroup.setProperty(TestElement.TEST_CLASS, TEST_CLASS_NAME);
        // 设置GUI类名称
        threadGroup.setProperty(TestElement.GUI_CLASS, GUI_CLASS_NAME);
        // 设置启用
        threadGroup.setEnabled(true);
        // 设置线程组名称
        threadGroup.setName(JmeterOptional.ofNullable(this.name).orElse("测试线程组"));
        // 设置线程组注释
        threadGroup.setComment(JmeterOptional.ofNullable(this.name).orElse(""));
        // 设置线程数量（用户数）
        threadGroup.setNumThreads(JmeterOptional.ofNullable(this.threadNum).orElse(1));
        // 设置到达线程数量（用户数）的时间
        threadGroup.setRampUp(JmeterOptional.ofNullable(this.rampUp).orElse(0));
        // 设置是否相同用户
        threadGroup.setIsSameUserOnNextIteration(JmeterOptional.ofNullable(this.isSameUser).orElse(Boolean.FALSE));
        // 设置是否启用调度器
        threadGroup.setScheduler(JmeterOptional.ofNullable(this.isScheduler).orElse(Boolean.FALSE));
        // 如果持续时间不为空，则设置持续时间
        JmeterOptional.ofNullable(this.duration).ifPresent(threadGroup::setDuration);
        // 如果启动延迟不为空，则设置启动延迟
        JmeterOptional.ofNullable(this.delay).ifPresent(threadGroup::setDelay);
        // 设置采样控制器
        threadGroup.setSamplerController(JmeterOptional.ofNullable(this.loopController).orElse(JmeterFactory.createLoopController()).create());
        // 返回线程组
        return threadGroup;
    }
}
